/*
*    l3qd - Light, light, lightweight queue
*    Copyright (C) 2024  Marcus Pedersén marcus@marcux.org
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package common

import (
	"fmt"
)

// Shared version and copyright
// for both daemon, client and node
const VERSION string = "0.0.1"
const COPYRIGHT string = "Copyright (C) 2023-2024 Marcus Pedersén."

// Prints L3Q in ascii
func AsciiL3q() {
	fmt.Println(" _    ____ ___")
	fmt.Println("| |  |__ // _ \\")
	fmt.Println("| |__ |_ \\ (_) |")
	fmt.Println("|____|___/\\__\\_\\")
	fmt.Println("")
}

// This is the different states
// that a job can be in.
type JobState int

const (
	JobStateQueued JobState = iota
	JobStateRunning
	JobStateDepend
	JobStateCancel
	JobStateTerminated
	JobStateCanceled
	JobStateError
	JobStateNodeError
	JobStateDependError
)

func (j JobState) String() string {
	states := [...]string{"Queued",
		"Running",
		"Depend",
		"Cancel",
		"Terminated",
		"Canceled",
		"Error",
		"NodeError",
		"DependError",
	}

	if j < JobStateQueued || j > JobStateDependError {
		return fmt.Sprintf("JobState(%d)", int(j))
	}

	return states[j]
}

func (j JobState) IsValid() bool {
	switch j {
	case JobStateRunning, JobStateQueued, JobStateDepend, JobStateTerminated, JobStateCancel, JobStateCanceled, JobStateError, JobStateNodeError, JobStateDependError:
		return true
	}

	return false
}

// This is the different types
// a job can have.
type JobType int

const (
	JobTypeSequence JobType = iota
	JobTypeParallel
)

func (t JobType) String() string {
	types := [...]string{"Sequence", "Parallel"}
	if t < JobTypeSequence || t > JobTypeParallel {
		return fmt.Sprintf("JobType(%d)", int(t))
	}

	return types[t]
}

func (t JobType) IsValid() bool {
	switch t {
	case JobTypeSequence, JobTypeParallel:
		return true
	}

	return false
}

// This is the different states
// that a node can be in.
type NodeState int

const (
	NodeStateRegister NodeState = iota
	NodeStateOnline
	NodeStateSoftOnline
	NodeStateOffline
	NodeStateMaintenance
	NodeStateMaintenanceDrain
)

func (n NodeState) String() string {
	states := [...]string{"Register",
		"Online",
		"SoftOnline",
		"Offline",
		"Maintenance",
		"MaintenanceDraining",
	}

	if n < NodeStateRegister || n > NodeStateMaintenanceDrain {
		return fmt.Sprintf("NodeState(%d)", int(n))
	}

	return states[n]
}

func (n NodeState) IsValid() bool {
	switch n {
	case NodeStateRegister, NodeStateOnline, NodeStateSoftOnline, NodeStateOffline, NodeStateMaintenance, NodeStateMaintenanceDrain:
		return true
	}

	return false
}

// Information about a node
type Node struct {
	Id          int       `json:"id"`
	Ip          string    `json:"ip"`
	Port        int       `json:"port"`
	Hostname    string    `json:"hostname"`
	Name        string    `json:"name"`
	CpusTotal   int       `json:"cpus_total"`
	CpusUsed    int       `json:"cpus_used"`
	CpusAlloc   int       `json:"cpus_alloc"`
	MemoryTotal uint64    `json:"memory_total"`
	MemoryUsed  uint64    `json:"memory_used"`
	SwapTotal   uint64    `json:"swap_total"`
	SwapUsed    uint64    `json:"swap_used"`
	State       NodeState `json:"state"`
	Key         string    `json:"-"`
	DaemonKey   string    `json:"-"`
	Tasks       []Task    `json:"Tasks"`
}

// Information about a job
type Job struct {
	Id              int      `json:"id"`
	Name            string   `json:"name" form:"name"`
	Type            JobType  `json:"type" form:"type"`
	InitDate        string   `json:"init_date"`
	StartDate       string   `json:"start_date"`
	EndDate         string   `json:"end_date"`
	RunTime         string   `json:"run_time"`
	HostsAlloc      int      `json:"hosts_alloc" form:"hosts_alloc"`
	CoresAlloc      int      `json:"cores_alloc" form:"cores_alloc"`
	NoTasksRunning  int      `json:"no_tasks_running"`
	NoTasksFinished int      `json:"no_tasks_finished"`
	NoTasksErr      int      `json:"no_tasks_err"`
	NoTasksTotal    int      `json:"no_tasks_total"`
	Nodes           string   `json:"nodes"`
	Depend          string   `json:"depend" form:"depend"`
	User            string   `json:"user" form:"user"`
	Group           string   `json:"group" form:"group"`
	State           JobState `json:"state"`
	Tasks           []Task   `json:"tasks" form:"tasks"`
}

// Information about a task
// Task is a part of a job
type Task struct {
	Id            int    `json:"id"`
	Command       string `json:"command" form:"command"`
	Seqno         int    `json:"seqno" form:"seqno"`
	Cores         int    `json:"cores" form:"cores"`
	MemoryLimit   uint64 `json:"memory_limit" form:"memory_limit"`
	WorkDir       string `json:"work_dir" form:"work_dir"`
	Unitname      string `json:"unitname"`
	StartTime     string `json:"start_time"`
	EndTime       string `json:"end_time"`
	RunTime       string `json:"run_time"`
	MonoStartTime int    `json:"mono_start_time"`
	MonoEndTime   int    `json:"mono_end_time"`
	ActiveState   string `json:"active_state"`
	SubState      string `json:"substate"`
	ExitCode      int    `json:"exit_code"`
	MainPid       int    `json:"main_pid"`
	MemoryPeak    uint64 `json:"memory_peak"`
	PidsPeak      int    `json:"pids_peak"`
	Stdout        string `json:"stdout"`
	Stderr        string `json:"stderr"`
	JobID         uint   `json:"jobid" gorm:"not null"`
	NodeID        uint   `json:"nodeid"`
}

// Task that is sent
// to node and managed by node.
type NodeTask struct {
	Task  Task   `json:"task"`
	User  string `json:"user"`
	Group string `json:"group"`
	Error string `json:"error"`
}

// Returned value if
// request fails
type FailResponse struct {
	Message string `json:"message"`
}

// Returned id if request
// requires an id in response
type IdResponse struct {
	Id uint `json:"id"`
}

// Key response at validation
// Key is for host to use
// at requests
type KeyResponse struct {
	Key string `json:"key"`
}
